using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace Smled
{
    public class TileSet
    {
        private List<Tile> mList;
        private System.Drawing.Image gray;
        private int tileSize = 32;
        private int version = 0;
        private int tileNum = 0;
        private INIGroup iniDesc = null;
        public const int META_VERSION = 1;

        public int TileSize { get { return tileSize; } set { tileSize = value; } }

        public TileSet()
        {
            gray = new System.Drawing.Bitmap(32, 32);
            System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(gray);
            g.Clear(System.Drawing.Color.Gray);
            g.Flush();

            mList = new List<Tile>();
        }

        public TileSet(string FileName)
        {
            gray = new System.Drawing.Bitmap(32, 32);
            System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(gray);
            g.Clear(System.Drawing.Color.Gray);
            g.Flush();

            //try
            //{
                LoadFromFile(FileName);
            //}
            //catch (Exception e)
            //{
              //  System.Diagnostics.Debug.WriteLine(e);
                //throw new Exception("Error loading from file!");
            //}
        }

        private void LoadMetaData(FileStream fs)
        {
            INIFile ini = new INIFile(fs);
            INIGroup g = null;

            while ((g = ini.getNext()) != null)
            {
                if (g.title == "General")
                {
                    tileSize = g.getInteger("TileSize", 32);
                    version = g.getInteger("Version", 1);
                    tileNum = g.getInteger("TileCount", 0);
                    iniDesc = g;
                }
            }

            fs.Close();
        }

        private void UpdateDesc()
        {
            if (iniDesc == null) iniDesc = new INIGroup("General");
            iniDesc.set("TileSize", tileSize.ToString());
            iniDesc.set("Version", META_VERSION.ToString());
            iniDesc.set("TileCount", mList.Count.ToString());
        }

        private void WriteMetaData(StreamWriter sw)
        {
            UpdateDesc();
            iniDesc.WriteToStream(sw);
        }

        private void LoadFromFile(string FileName)
        {
            libACO.ACOarchive arc = new libACO.ACOarchive(FileName);
            string datF = Path.GetTempFileName(), imgF;
            bool advFormat = arc.FileExists("meta.txt");
            bool metaFormat = arc.FileExists("tileset.dat");

            if(!metaFormat) arc.ExtractFileAs("index.dat", datF);
            

            if (metaFormat) LoadMetaData(arc.GetFileStream("tileset.dat"));

            if (metaFormat)
            {
                INIFile ini = new INIFile(arc.GetFileStream("tileset.dat"), true);
                INIGroup g = null;
                mList = new List<Tile>();

                while ((g = ini.getNext()) != null)
                {
                    if (g.title == "Tile")
                    {
                        Tile t = new Tile(this, g);
                        imgF = Path.GetTempFileName() + ".png";
                        string pngName = t.ID.ToString() + ".png";

                        try
                        {
                            arc.ExtractFileAs(pngName, imgF);
                            t.TileImage = new System.Drawing.Bitmap(imgF);
                            //File.Delete(imgF);
                        }
                        catch (Exception e)
                        {
                            System.Diagnostics.Debug.WriteLine(e);
                            System.Diagnostics.Debug.WriteLine("pngName = " + pngName);
                            System.Diagnostics.Debug.WriteLine("imgF = " + imgF);
                            t.TileImage = gray;
                        }

                        mList.Add(t);
                    }
                }
            }
            else
            {
                StreamReader sr = new StreamReader(datF);
                string tmp = sr.ReadLine();
                int num = Int32.Parse(tmp);

                mList = new List<Tile>();
                for (int i = 0; i < num; ++i)
                {
                    Tile t = new Tile(this);
                    tmp = sr.ReadLine();
                    t.ID = Int32.Parse(tmp);
                    t.Name = sr.ReadLine();

                    if (advFormat)
                    {
                        t.FileChar = sr.ReadLine();
                        t.OffsetX = Int32.Parse(sr.ReadLine());
                        t.OffsetY = Int32.Parse(sr.ReadLine());
                    }

                    imgF = Path.GetTempFileName() + ".png";

                    try
                    {
                        arc.ExtractFileAs(t.ID.ToString() + ".png", imgF);
                        t.TileImage = new System.Drawing.Bitmap(imgF);
                        //File.Delete(imgF);
                    }
                    catch (Exception)
                    {
                        t.TileImage = gray;
                    }

                    mList.Add(t);
                    try
                    {
                        File.Delete(imgF);
                    }
                    catch (Exception) { }
                }

                sr.Close();
                File.Delete(datF);
            }
        }

        public Tile GetTile(int i)
        {
            foreach (Tile t in mList)
            {
                if (t.ID == i)
                {
                    return t;
                }
            }
            return null;
        }

        public void SaveToFile(string FileName)
        {
            string tmp = Path.GetTempPath();
            
            string datFile = Path.GetTempFileName();
            Stream datStream = new FileStream(datFile, System.IO.FileMode.Create);
            StreamWriter sw = new StreamWriter(datStream);
            
            sw.WriteLine(mList.Count);
            

            foreach (Tile t in mList)
            {
                t.WriteToStreamWriter(sw);
            }

            sw.Close();
            datStream.Close();

            string[] files = new string[mList.Count + 3];
            string[] names = new string[mList.Count + 3];

            files[0] = datFile; names[0] = "index.dat";
            string tmpFile = Path.GetTempFileName();
            FileStream fs = File.Create(tmpFile);
            fs.Close();
            files[1] = tmpFile; names[1] = "meta.txt";

            tmpFile = Path.GetTempFileName();
            fs = File.Create(tmpFile);
            StreamWriter ssw = new StreamWriter(fs);
            WriteMetaData(ssw);
            foreach (Tile t in mList)
            {
                t.WriteMeta(ssw);
            }
            ssw.Close();
            fs.Close();
            files[2] = tmpFile; names[2] = "tileset.dat";

            int i = 3;
            foreach (Tile t in mList)
            {
                files[i] = Path.GetTempFileName();
                try
                {
                    t.TileImage.Save(files[i], System.Drawing.Imaging.ImageFormat.Png);
                }
                catch (Exception) { }
                names[i] = t.ID.ToString() + ".png";
                i++;
            }
            //libACO.ACOarchive arc = new libACO.ACOarchive(FileName, new List<String>());
            //arc.AppendFileAs(datFile, "index.dat");
            libACO.ACOarchive arc = new libACO.ACOarchive(FileName, files, names);

            File.Delete(datFile);
        }

        public Tile AddNewTile()
        {
            Tile t = new Tile(this);
            mList.Add(t);
            return t;
        }

        public int GetLessOrEqual(int num)
        {
            int fnum = num;
            bool free = true;

            do
            {
                free = true;
                foreach (Tile t in mList)
                {
                    if (t.ID == fnum)
                    {
                        free = false;
                        fnum--;
                    }
                }
            } while (!free);

            if (fnum < 0) fnum = GetGreaterOrEqual(0);

            return fnum;
        }

        public int GetGreaterOrEqual(int num)
        {
            int fnum = num;
            bool free = true;

            do
            {
                free = true;
                foreach (Tile t in mList)
                {
                    if (t.ID == fnum)
                    {
                        free = false;
                        fnum++;
                    }
                }
            } while (!free);

            return fnum;
        }

        public List<Tile> Set
        {
            get
            {
                return mList;
            }
        }
    }
}
